package com.chuangke.common.utils;

import java.util.stream.IntStream;

/**
 * 身份证号码验证 
 * 1、号码的结构 
 * 公民身份号码是特征组合码，由十七位数字本体码和一位校验码组成。从左至右依次为：六位数字地址码，
 * 八位数字出生日期码，三位数字顺序码和一位数字校验码。
 *  2、地址码(前六位数）
 * 表示编码对象常住户口所在县(市、旗、区)的行政区划代码，按GB/T2260的规定执行。 
 * 3、出生日期码（第七位至十四位）
 * 表示编码对象出生的年、月、日，按GB/T7408的规定执行，年、月、日代码之间不用分隔符。
 *  4、顺序码（第十五位至十七位）
 * 表示在同一地址码所标识的区域范围内，对同年、同月、同日出生的人编定的顺序号， 顺序码的奇数分配给男性，偶数分配给女性。 
 * 5、校验码（第十八位数）
 * （1）十七位数字本体码加权求和公式 S = Sum(Ai Wi), i = 0, , 16 ，先对前17位数字的权求和 ;
 * Ai:表示第i位置上的身份证号码数字值; Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
 * （2）计算模 Y = mod(S, 11) 
 * （3）通过模( 0 1 2 3 4 5 6 7 8 9 10)得到对应的校验码 Y:1 0 X 9 8 7 6
 * 5 4 3 2
 */
public class IdentityUtils {

	// 身份证校验码
	private static final int[] COEFFICIENT_ARRAY = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };

	// 身份证号的尾数规则
	private static final String[] IDENTITY_MANTISSA = { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };

	private static final String IDENTITY_PATTERN = "^[0-9]{17}[0-9Xx]$";

	public static boolean isLegalPattern(String identity) {
		if (identity == null) {
			return false;
		}

		if (identity.length() != 18) {
			return false;
		}

		if (!identity.matches(IDENTITY_PATTERN)) {
			return false;
		}

		char[] chars = identity.toCharArray();
		long sum = IntStream.range(0, 17).map(index -> {
			char ch = chars[index];
			int digit = Character.digit(ch, 10);
			int coefficient = COEFFICIENT_ARRAY[index];
			return digit * coefficient;
		}).summaryStatistics().getSum();

		// 计算出的尾数索引
		int mantissaIndex = (int) (sum % 11);
		String mantissa = IDENTITY_MANTISSA[mantissaIndex];

		String lastChar = identity.substring(17);
        return lastChar.equalsIgnoreCase(mantissa);
	}
	
	public static void main(String[] args) {
		System.out.println(isLegalPattern("37131219861123693x")) ;
	}
}
